#include "Generate_C_std.h"
#include "Pattern_eval_expr_or_assign_var.h"



class Pattern_expr_method_invocation : public Pattern_eval_expr_or_assign_var
{
public:
	Expr* rhs_pattern()
	{
		rhs = new Wildcard<Method_invocation>;
		return rhs;
	}

	void generate_code (Generate_C* gen)
	{
		// The macros are paramatrized for the LHS. This descriptor says whether
		// the is no LHS, or, if there is, whether or not the assignment is
		// by-ref.
		String* lhs_descriptor;
		VARIABLE_NAME* lhs_var = NULL;
		if (lhs)
		{
			if (agn->is_ref)
				lhs_descriptor = s("REF");
			else
				lhs_descriptor = s("NO_REF");

			lhs_var = lhs->value;
		}
		else
		{
			lhs_descriptor = s("NONE");
		}

		// We want a list of rvalues here, not actual parameters. But we need to
		// communicate the is_ref field of the actual_parameter if its there.
		Object_list* params = new Object_list;
		foreach (Actual_parameter* ap, *rhs->value->actual_parameters)
		{
			params->push_back (ap->rvalue);
			if (ap->is_ref)
				ap->rvalue->attrs->set_true ("phc.codegen.is_ref");
		}

		
		// buf << "debug_hash(EG(active_symbol_table));\n";

		// Variable function or ordinary function?
		METHOD_NAME* name = dynamic_cast<METHOD_NAME*>(rhs->value->method_name);

		if (name == NULL)
		  {
		    phc_unsupported (rhs->value, "variable function");
		    buf << "TODOVariableFunction;" << endl;
		    
		    // Names of the runtime variables that will hold the (potentially cached)
		    // location of the function
		    string fci_name;
		    string fcic_name;
		    
		    string function_name;
		    
		    // Global function or class member?
		    if (rhs->value->target != NULL)
		      {
			VARIABLE_NAME* object_name = dynamic_cast<VARIABLE_NAME*>(rhs->value->target);
			CLASS_NAME* class_name  = dynamic_cast<CLASS_NAME*>(rhs->value->target);
			
			if(object_name != NULL)
			  {
				// TODO: if we statically knew the type of the object that is invoked
				// TODO: (type inference) then we should be able to use the cached 
				// TODO: function info. As it stands, we have to lookup the function
				// TODO: every time since the variable can be bound to a different
				// TODO: class every time we encounter this statement
				function_name = *"TODO";
				INST (buf, "method_invocation",
				      s(function_name),
				      params,
				      rhs->value->get_filename (),
	       s(lexical_cast<string> (rhs->value->get_line_number ())),
	       s(lexical_cast<string>(rhs->value->actual_parameters->size ())),
				      object_name,
				      lhs_descriptor,
				      lhs ? lhs->value : NULL);
				return;
			  }
			else
			  {
			    assert (class_name != NULL);
			    stringstream fqn;
			    fqn << *class_name->value << "::" << "TODO";
    fci_name  = suffix (suffix(*class_name->value, "TODO"), "fci");
    fcic_name = suffix (suffix(*class_name->value, "TODO"), "fcic");
			    function_name = fqn.str();
			  }
		      }
		    else
		      {
			fci_name  = suffix ("TODO", "fci");
			fcic_name = suffix ("TODO", "fcic");
			if (name)
			  {
			    function_name = *name->value;
			  }
			else
			  {
			    function_name = "TODO_variable_name";
			  }
		      }
		    INST (buf, "function_invocation",
			  s(function_name),
			  params,
			  rhs->value->get_filename (),
			  s(lexical_cast<string> (rhs->value->get_line_number ())),
			  s(fci_name),
			  s(fcic_name),
			  s(lexical_cast<string>(rhs->value->actual_parameters->size ())),
			  lhs_descriptor,
			  lhs ? lhs->value : NULL);
		  }
		else
		  {
		// Names of the runtime variables that will hold the (potentially cached)
		// location of the function
		string fci_name;
		string fcic_name;

		string function_name;

		// Global function or class member?
		if (rhs->value->target != NULL)
		{
			VARIABLE_NAME* object_name = dynamic_cast<VARIABLE_NAME*>(rhs->value->target);
			CLASS_NAME* class_name  = dynamic_cast<CLASS_NAME*>(rhs->value->target);

			if(object_name != NULL)
			{
				// TODO: if we statically knew the type of the object that is invoked
				// TODO: (type inference) then we should be able to use the cached 
				// TODO: function info. As it stands, we have to lookup the function
				// TODO: every time since the variable can be bound to a different
				// TODO: class every time we encounter this statement
		

			  if (name)
			    {
			      function_name = *name->value;
			    }
			  else
			    {
			      function_name = "TODO_variable_name";
			    }

				INST (buf, "method_invocation",
						s(function_name),
						params,
						rhs->value->get_filename (),
						s(lexical_cast<string> (rhs->value->get_line_number ())),
						s(lexical_cast<string>(rhs->value->actual_parameters->size ())),
						object_name,
						lhs_descriptor,
						lhs ? lhs->value : NULL);

				return;
			}
			else
			{
				assert (class_name != NULL);

				stringstream fqn;

				if (name)
				  {
				    fqn << *class_name->value << "::" << *name->value;
				    fci_name  = suffix (suffix(*class_name->value, *name->value), "fci");
				    fcic_name = suffix (suffix(*class_name->value, *name->value), "fcic");
				    function_name = fqn.str();

				  }
				else
				  {
				    function_name = "TODO_FQN";
				  }			  
				
			}
		}
		else
		{
		  if (name)
		    {
		      fci_name  = suffix (*name->value, "fci");
		      fcic_name = suffix (*name->value, "fcic");
		      function_name = *name->value;
		    }
		  else
		    {
		      function_name = "TODO";
		    }
		}

		INST (buf, "function_invocation",
				s(function_name),
				params,
				rhs->value->get_filename (),
				s(lexical_cast<string> (rhs->value->get_line_number ())),
				s(fci_name),
				s(fcic_name),
				s(lexical_cast<string>(rhs->value->actual_parameters->size ())),
				lhs_descriptor,
				lhs ? lhs->value : NULL);

		  }

	}

protected:
	Wildcard<Method_invocation>* rhs;
};

CREATE(Pattern_expr_method_invocation);
